package MDVRPTW;

import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Label;
import java.awt.Panel;
import java.awt.TextArea;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;

import org.apache.commons.lang3.math.NumberUtils;


public class MDVRPTWExample extends JFrame{

	public static final String fileName="testcase";//选择的测试集
	public static final int tolCount=50000;//外循环次数
	public static final int inCount=80;//内循环次数
	public MDVRPTW mdvrptw;//测试用例模型集
	public Population pops;//MOSA生成的结果
	public int mapSize=2000;//画图窗口最大像素
	public int kesize=20;
	TextField p1;// 显示程序运行时间
	TextField p2;// 显示Pareto解集解的个数，一个解代表一个线路安排方案
	TextField p3;// 显示单前方案的编号
	TextArea content = new TextArea(18, 40);// 展示目标值和路径
	
	MDVRPTWExample(){
		mdvrptw=new MDVRPTW(fileName);
		MOSA mosa=new MOSA(mdvrptw);
		mosa.initial();
		pops=mosa.run(tolCount, inCount);
	}
	
	public static void main(String[] args) {
		
		long startTime = System.currentTimeMillis();//记录开始时间
		WelcomeFrame wf = new WelcomeFrame();// 运行程序执行提示窗体
		MDVRPTWExample mdvrptwExample=new MDVRPTWExample();//运行主界面		
		wf.closeFrame();// 主程序执行完关闭提示窗体
		long endTime = System.currentTimeMillis();//记录结束时间
		long programTime = (endTime - startTime) / 1000;
		mdvrptwExample.p1=new TextField("" + programTime + "秒");
		mdvrptwExample.p2=new TextField(""+mdvrptwExample.pops.getParetoSet().size());
		mdvrptwExample.p3=new TextField("1");
		mdvrptwExample.init();
	}
	
	public void init(){
		this.setTitle("PDMOSA求解MO-MDVRPTW仿真实验结果展示");
		this.setBounds(150, 150, 600, 800);
		this.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				System.exit(0);
			}
		});
		Panel panel = new Panel();
		Label prompt1 = new Label("本次PDMOSA求解MO-MDVRPTW执行的时间为：", Label.LEFT);
		Label prompt2 = new Label("Pareto前沿上的最优解个数：", Label.LEFT);
		Label prompt3 = new Label("当前Pareto解为：");
		Button pre = new Button("上一个");
		pre.addActionListener(new PrevMonitor());
		Button next = new Button("下一个");
		next.addActionListener(new NextMonitor());
		Button show = new Button("查看路线图");
		show.addActionListener(new ShowLineMonitor());
		p1.setEditable(false);
		p2.setEditable(false);
		p3.setText("1");
		p3.addKeyListener(new PressMonitor());
		
		Solution sol=pops.getParetoSet().get(0);
		content.setText("");
		content.append("    本方案使用车辆数为:"+sol.getTotalCars()+"\r\n");
		content.append("    本方案总路程为:"+sol.getTotalDistance()+"\r\n");
		content.append("    本方案时间窗违背程度为:"+sol.getTotalVoilation()+"\r\n");
		content.append("    本方案车辆间服务方差为:"+sol.getTimeVariance()+"\r\n");
		content.append("-----------------------------------------------------------------------------------------------------\n");
		for (Car car : sol.getCars()) {
			content.append("车场"+car.getRoute().get(0).getNum()+"路程为:"+car.getDistance()+"  时间窗违背程度为:"+car.getVoilation()+" 路径为:\r\n");
			String s="";
			for (Customer csm : car.getRoute()) {
				s+=""+csm.getNum()+"  ";
			}
			s+="\n";
			content.append(s);
		}
		content.setSelectionStart(0);

		panel.add(prompt1);
		panel.add(p1);
		panel.add(prompt2);
		panel.add(p2);
		panel.add(prompt3);
		panel.add(p3);
		panel.add(pre);
		panel.add(next);
		panel.add(show);
		this.add(panel, BorderLayout.NORTH);
		this.add(content, BorderLayout.SOUTH);
		this.pack();
		
		this.setVisible(true);
	}
	
	class PressMonitor implements KeyListener{

		@Override
		public void keyPressed(KeyEvent e) {
			
			if(e.getKeyCode()==KeyEvent.VK_ENTER){
				String str=p2.getText().trim();
				if(NumberUtils.isNumber(str)){
					int i = Integer.parseInt(p3.getText().trim());
					int tol = Integer.parseInt(p2.getText().trim());
					if(i>1&&i<tol){
						p3.setText(""+i);
						Solution sol=pops.getParetoSet().get(i-1);
						content.setText("");
						content.append("    本方案使用车辆数为:"+sol.getTotalCars()+"\r\n");
						content.append("    本方案总路程为:"+sol.getTotalDistance()+"\r\n");
						content.append("    本方案时间窗违背程度为:"+sol.getTotalVoilation()+"\r\n");
						content.append("    本方案车辆间服务方差为:"+sol.getTimeVariance()+"\r\n");
						content.append("-----------------------------------------------------------------------------------------------------\n");
						for (Car car : sol.getCars()) {
							content.append("车场"+car.getRoute().get(0).getNum()+"路程为:"+car.getDistance()+"  时间窗违背程度为:"+car.getVoilation()+" 途径:\r\n");
							String s="";
							for (Customer csm : car.getRoute()) {
								s+=""+csm.getNum()+"  ";
							}
							s+="\n";
							content.append(s);
						}
						content.setSelectionStart(0);
					}
				}
			}
		}

		@Override
		public void keyTyped(KeyEvent e) {
			
		}

		@Override
		public void keyReleased(KeyEvent e) {
			
		}
	}
	
	//上一个Pareto解的监听
	class PrevMonitor implements ActionListener{
		@Override
		public void actionPerformed(ActionEvent e) {

			int i = Integer.parseInt(p3.getText().trim());
			int tol = Integer.parseInt(p2.getText().trim());
			if(i>1){
				p3.setText(""+(i-1));
				Solution sol=pops.getParetoSet().get(i);
				content.setText("");
				content.append("    本方案使用车辆数为:"+sol.getTotalCars()+"\r\n");
				content.append("    本方案总路程为:"+sol.getTotalDistance()+"\r\n");
				content.append("    本方案时间窗违背程度为:"+sol.getTotalVoilation()+"\r\n");
				content.append("    本方案车辆间服务方差为:"+sol.getTimeVariance()+"\r\n");
				content.append("-----------------------------------------------------------------------------------------------------\n");
				for (Car car : sol.getCars()) {
					content.append("车场"+car.getRoute().get(0).getNum()+"路程为:"+car.getDistance()+"  时间窗违背程度为:"+car.getVoilation()+" 途径:\r\n");
					String s="";
					for (Customer csm : car.getRoute()) {
						s+=""+csm.getNum()+"  ";
					}
					s+="\n";
					content.append(s);
				}
				content.setSelectionStart(0);
			}
		}
	}
	
	//下一个Pareto解的监听
	class NextMonitor implements ActionListener{
		@Override
		public void actionPerformed(ActionEvent e) {

			int i = Integer.parseInt(p3.getText().trim());
			int tol = Integer.parseInt(p2.getText().trim());
			if(i<tol){
				p3.setText(""+(i+1));
				Solution sol=pops.getParetoSet().get(i);
				content.setText("");
				content.append("    本方案使用车辆数为:"+sol.getTotalCars()+"\r\n");
				content.append("    本方案总路程为:"+sol.getTotalDistance()+"\r\n");
				content.append("    本方案时间窗违背程度为:"+sol.getTotalVoilation()+"\r\n");
				content.append("    本方案车辆间服务方差为:"+sol.getTimeVariance()+"\r\n");
				content.append("-----------------------------------------------------------------------------------------------------\n");
				for (Car car : sol.getCars()) {
					content.append("车场"+car.getRoute().get(0).getNum()+"路程为:"+car.getDistance()+"  时间窗违背程度为:"+car.getVoilation()+" 途径:\r\n");
					String s="";
					for (Customer csm : car.getRoute()) {
						s+=""+csm.getNum()+"  ";
					}
					s+="\n";
					content.append(s);
				}
				content.setSelectionStart(0);
			}
		}
	}
	
	//显示路径图的监听
	class ShowLineMonitor implements ActionListener{

		public void actionPerformed(ActionEvent e) {
			LineFrame lf=new LineFrame();
		}
	}
	
	//路径图窗体
	class LineFrame extends Frame{
		public LineFrame(){
			this.setTitle("路线图");
			LinePanel linePanel=new LinePanel();
			JScrollPane scrollPane=new JScrollPane(linePanel);
			this.setSize(1000, 1000);
			this.add(scrollPane);
			this.addWindowListener(new WindowAdapter() {
				@Override
				public void windowClosing(WindowEvent e) {
					dispose();
				}
			});
			this.setVisible(true);
		}
	}
	
	
	// 定义一个内部类，展示路线集合图
	class LinePanel extends JPanel {
		//硬编码，选出10种颜色，比测试用例集中的车场数都多，用于画图
		Color[] colors={Color.blue,Color.cyan,Color.gray,Color.green,Color.lightGray,Color.magenta,Color.orange,Color.pink,Color.red,Color.yellow};
		// 覆盖JPanel的paint方法
		// Graphics 是绘图的重要类
		public void paint(Graphics g) {
			// 调用父类函数完成初始化
			// 这句话不能少
			super.paint(g);
			//设置默认大小
			this.setPreferredSize(new Dimension(10200, 10200));

			darwXY(g);	
			drawCustomer(g, mdvrptw);		
			drawDeport(g, mdvrptw);
			drawLine(g);
		}
		
		//画出路径
		protected void drawLine(Graphics g) {
			int index=Integer.parseInt(p3.getText().trim())-1;
			for (Car car : pops.getParetoSet().get(index).getCars()) {
				Graphics2D g2 = (Graphics2D)g;  //g是Graphics对象  
	            g2.setStroke(new BasicStroke(3.0f));
				g2.setColor(colors[car.getRoute().get(0).getNum()-mdvrptw.customers.size()-1]);
				for(int i=0;i<car.getRoute().size()-1;i++){
					g2.drawLine(exChange(car.getRoute().get(i).getX()), exChange(-car.getRoute().get(i).getY()), exChange(car.getRoute().get(i+1).getX()), exChange(-car.getRoute().get(i+1).getY()));
				}
			}
		}
		
		//将点的坐标值转换为Jpanel的坐标值
		protected int exChange(double z){
			return (int)(100+(double)mapSize/2+z*(double)(mapSize/200));
		}

		//画出车场位置
		protected void drawDeport(Graphics g, MDVRPTW mdvrptw) {
			g.setFont(new Font("", Font.BOLD, 20));
			for (Deport dpt : mdvrptw.deports) {
				g.setColor(colors[dpt.getNum()-mdvrptw.customers.size()-1]);
				g.fillRect(exChange(dpt.getX())-5, exChange(-dpt.getY())-5, 10, 10);
				g.drawString(""+dpt.getNum(), exChange(dpt.getX()), exChange(-dpt.getY()));
			}
		}

		//画出顾客位置
		protected void drawCustomer(Graphics g, MDVRPTW mdvrptw) {
			//设置画笔颜色，字体大小
			g.setColor(Color.black);
			g.setFont(new Font("", Font.BOLD, 20));
			for (Customer csm : mdvrptw.customers) {
				g.fillOval(exChange(csm.getX())-5, exChange(-csm.getY())-5, 10, 10);
				g.drawString(""+csm.getNum(), exChange(csm.getX()), exChange(-csm.getY()));
			}
		}

		protected void darwXY(Graphics g) {
			//设置画笔颜色，字体大小
			g.setColor(Color.black);
			g.setFont(new Font("", Font.BOLD, 20));
			//画X轴以及刻度
			g.drawLine(100, mapSize+100, mapSize+150, mapSize+100);
			for(int i=0;i<=kesize;i++){
				g.drawLine(100+i*mapSize/kesize, 100+mapSize, 100+i*mapSize/kesize, 105+mapSize);
				g.drawString(""+(-100+i*200/kesize), 100+i*mapSize/kesize, 125+mapSize);
			}
			//画Y轴以及刻度
			g.drawLine(100, mapSize+100, 100, 50);
			for(int i=0;i<=kesize;i++){
				g.drawLine(100, 100+mapSize-i*mapSize/kesize, 95, 100+mapSize-i*mapSize/kesize);
				g.drawString(""+(-100+i*200/kesize), 55, 100+mapSize-i*mapSize/kesize);
			}
		}
	}
}

class WelcomeFrame extends Frame {

	JProgressBar jpb;

	public WelcomeFrame() {
		this.setTitle("Start!");
		this.setBounds(280, 200, 300, 250);
		this.setResizable(false);
		this.add(new Label("温馨提示：PDMOSA正在执行求解MDVRPTW中，请耐心等待！"),
				BorderLayout.NORTH);
		/**
		 * 创建一个不确定模式的进度条
		 */
		jpb = new JProgressBar();
		jpb.setIndeterminate(true); // 设置进度条为不确定模式,默认为确定模式
		jpb.setStringPainted(true);
		jpb.setString("PDMOSA正在执行求解MDVRPTW中......");
		this.add(jpb, BorderLayout.SOUTH);
		this.pack();
		this.setVisible(true);
	}

	public void closeFrame() {
		jpb.setIndeterminate(false);
		jpb.setString("OK！PDMOSA已执行完毕！");
		try {
			Thread.sleep(1500);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		this.setVisible(false);
		this.dispose();
	}

}